/* * TestValidator.java * * Created on October 25, 2006 * Latest version: October 25, 2006 * * This class is a part of the Assessment of Comprehension program (AoC), created * for the Language Science Lab at Boston University, under the grant entitled * "Assessment of Comprehension Skills in Older Struggling Readers." Please * direct any questions regarding the project to Gloria S. Waters or David N. * Caplan. * * This program was written by Sam Fentress [add any subsequent authors here]. * Questions about the program may be directed to sfentress@gmail.com. * * This program is released WITHOUT COPYRIGHT into the PUBLIC DOMAIN. This * program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * @author Sam Fentress * @version 0.05 */ package engine; import gui.Gui; import sam.fileprocessing.Folders; import sam.utilities.xml.myXML; import sam.utilities.ArrayUtils; import sam.utilities.Logger; import java.io.File; import java.io.FileWriter; import java.io.PrintWriter; import java.io.FileReader; import java.io.BufferedReader; /** * Checks stimulus files for errors. Checks to see that all image and sound files requested by the stim files exist and are in the right places. * @author Sam Fentress * @version 0.01 */ public class TestValidator { boolean areTestsOk; String statusMessage, errorMessage; File xmlFile; /** Creates a new instance of TestValidator */ public TestValidator() { statusMessage = ""; errorMessage = ""; xmlFile = null; } /** * Runs through all stim files and checks for accuracy. * @return True if all stim files are well-formatted and image and sound files exist. */ public boolean validateTests(){ areTestsOk = true; File[] stimFiles = Folders.getFilesFromFolder("Stimuli","csv",true); int numFiles = stimFiles.length; try{ myXML test = new myXML("test"); test.setXMLComment("<!-- Validation file for Assessment Of Comprehension program, v. 0.05.3 or later -->"); for (int i = 0; i < stimFiles.length; i++) { myXML subtest = test.addElement("subtest"); myXML name = subtest.addElement("name",stimFiles[i].getName()); myXML update = subtest.addElement("last_updated",new Long(stimFiles[i].lastModified())); boolean isTestOk = validateFile(stimFiles[i]); if (!isTestOk) areTestsOk = false; myXML valid = subtest.addElement("valid", new Boolean(isTestOk)); } new File("Documents").mkdirs(); PrintWriter pw = new PrintWriter(new FileWriter("Documents" + File.separator + "validation.xml"), true); test.serialize(pw); } catch (myXML.myXMLException e){ areTestsOk = false; errorMessage += "Could not create XML file"; Logger.log(e.toString()); } catch (java.io.IOException e){ areTestsOk = false; errorMessage += "Could not create FileWriter or BufferedWriter"; Logger.log(e.toString()); } if (areTestsOk) statusMessage = "Success! Tests are all valid"; else statusMessage = "Warning: Errors were found in one or more tests"; return areTestsOk; } /** * Checks individual stim file. * @param file Filename of stim file to be checked. * @return True if stim file is well-formatted and image and sound files exist. */ public boolean validateFile(File file){ boolean isFileOk = true; try { ValueList list = new ValueList(file); list.setName(file.getName()); boolean isTypeOk = Gui.checkType(list.getType()); Logger.log(list.getName() + " checking type"); if (!isTypeOk){ errorMessage += " - The test type \"" + list.getType() + "\" in " + file.getName() + " is not a valid test type.\n"; isFileOk = false; } if (list.hasSound()){ Logger.log(list.getName() + " checking sound"); int numStimuli = 0; if ((list.getType().toLowerCase().indexOf("one_word") == 0) || (list.getType().toLowerCase().indexOf("one_sent") == 0) || (list.getType().toLowerCase().indexOf("para") == 0)) numStimuli = 1; else if (list.getType().toLowerCase().indexOf("two_words") == 0) numStimuli = 2; // need to have _mw_ if (list.hasExamples()){ for (int i = 0; i < list.getNumExamples(); i++) { for (int j = 0; j < numStimuli; j++) { String soundFile = list.getExamplesNo(i)[j]; File f = new File("Sounds" + File.separator + soundFile); if (!(list.getType().toLowerCase().indexOf("para") == 0) && !(soundFile.toLowerCase().endsWith(".wav"))) if (!f.exists()){ errorMessage += " - The sound \"" + soundFile + ",\" used in " + file.getName() + ", could not be found in \\Sounds\n"; isFileOk = false; } } } } int startStimNumber = 0; if (list.hasTags()) startStimNumber += list.getNumTags(); for (int i = 0; i < list.getNumValues(); i++) { for (int j = startStimNumber; j < numStimuli+startStimNumber; j++) { String soundFile = list.getValueNo(i)[j]; File f = new File("Sounds" + File.separator + soundFile); if (!(list.getType().toLowerCase().indexOf("para") == 0) && !(soundFile.toLowerCase().endsWith(".wav"))) if (!f.exists()){ errorMessage += " - The sound \"" + soundFile + ",\" used in " + file.getName() + ", could not be found in \\Sounds\n"; isFileOk = false; } } } } if (list.getType().toLowerCase().indexOf("two_picts") > 0){ if (list.hasExamples()){ for (int i = 0; i < list.getNumExamples(); i++) { String[] imageFiles = list.getExamplesNo(i); for (int j = imageFiles.length - 2; j < imageFiles.length; j++) { String imageFile = imageFiles[j]; File f = new File("Images" + File.separator + imageFile); if (!f.exists()){ errorMessage += " - The image \"" + imageFile + ",\" used in " + file.getName() + ", could not be found in \\Images\n"; isFileOk = false; } } } } for (int i = 0; i < list.getNumValues(); i++) { String[] imageFiles = list.getValueNo(i); Logger.log(ArrayUtils.toString(imageFiles)); for (int j = imageFiles.length - 2; j < imageFiles.length; j++) { String imageFile = imageFiles[j]; File f = new File("Images" + File.separator + imageFile); if (!f.exists()){ errorMessage += " - The image \"" + imageFile + ",\" used in " + file.getName() + ", could not be found in \\Images\n"; isFileOk = false; } } } } } catch (ArrayIndexOutOfBoundsException e){ errorMessage += " - " + file.getName() + " is not properly formatted.\nMake sure to include both a Test Type and the " + "test's instructions. Read the user manual for instructions on how to format a test.\n"; isFileOk = false; StackTraceElement[] trace = e.getStackTrace(); Logger.log(e + " at " + trace[0].toString() + ", " + trace[1].toString() + ", " + trace[2].toString()); } // String instructions = list.getInstructions(); // if (instructions.length() ) return isFileOk; } /** * Reads validation XML file, checks to see that it is up-to-date, and, if up-to-date, whether all stim files were well-formatted. * @return True if XML validation file exists, it is up-to-date, and all stim files were well-formatted. */ public boolean checkValidation(){ areTestsOk = true; myXML xmlRoot; File xmlFile = new File("Documents" + File.separator + "validation.xml"); if (xmlFile.exists()){ try{ BufferedReader in = new BufferedReader(new FileReader("Documents" + File.separator + "validation.xml")); xmlRoot = new myXML((BufferedReader)in); } catch (Exception e){ statusMessage = "Warning: Could not read validation file"; return false; } } else{ areTestsOk = false; statusMessage = "Warning: Tests have not yet been validated."; return false; } File[] stimFiles = Folders.getFilesFromFolder("Stimuli","csv",true); int numFiles = stimFiles.length; for (int i = 0; i < stimFiles.length; i++) { long lastUpdated = stimFiles[i].lastModified(); myXML xmlSubtest = xmlRoot.getElement(i); myXML xmlLastUpdated = xmlSubtest.findElement("last_updated"); if (lastUpdated > Long.parseLong(xmlLastUpdated.getValue())){ statusMessage = "Warning: Validation is not up to date."; return false; } myXML xmlValid = xmlSubtest.findElement("valid"); if (xmlValid.getValue().equalsIgnoreCase("false")){ statusMessage = "Warning: Errors were found in one or more tests"; return false; } } statusMessage = "Tests have been validated and are up to date"; return areTestsOk; } /** * * @return String describing status of validation to the user. */ public String getStatus(){return statusMessage;} /** * * @return String describing error message to user. */ public String getErrorMessage(){return errorMessage;} public void clearErrorMessage(){errorMessage = "";} /** * Checks to see if student has already started test, by comparing student name with name on saved data files. If student has taken test, program will re-start from last sub-test. * @param student Student currently taking test * @return True if student has already started the test. */ public static boolean checkIfAlreadyBegun(Student student){ String studentFilenameBegining = student.getLastName() + student.getFirstName().substring(0,1); File[] studentResults = Folders.getFilesBeginningWith("Results" + File.separator + studentFilenameBegining, studentFilenameBegining, "csv"); if (studentResults.length > 0) return true; else return false; } }